module Explode.GameTitleState;
private import Explode.Stage;
private import Explode.Player;
private import Explode.GameConfig;
private import Explode.GameState;
private import Explode.ReplayGameState;
private import Explode.Editor;
private import Explode.DemoGameState;
private import Form.MenuItem;
private import State.IState;
private import Input.KeyCode;
private import Input.GamePad;
private import Graphics.IGraphics;
private import Sound.Manager;
private import System.Console;
private import System.BootInfo;
private import std.file;
private import std.string;


/**
*	タイトル画面用
*/
private class GameTitleState : BasicState {
	protected const int WIDTH = 240 , HEIGHT = 480;

	private class Background : IDrawingEntry{
		public float x(){return 0;}
		public float y(){return 0;}
		public float z(){return 250;}
		public bool drawingEntry( IGraphics g ){
			return g.addDrawingEntry( this );
			
		} //
		public bool draw( IGraphics g ){
			g.setViewport( 0 , 0, WIDTH , HEIGHT );
			g.drawFilledRect( 0 , 0 , WIDTH , HEIGHT , Color.create(0x33000000u) );
			g.drawFilledRect( ( WIDTH - 16*14 )/2 , 100 , 16 * 14 , 100 , Color.create(0xcc000000u) );
			g.drawText( "Explode Runner" , ( WIDTH - 16*14 )/2 , 130 , Color.create( 0x66ffffffu ) , 16 , 64 );
			g.drawText( "Explode Runner" , ( WIDTH - 16*14 )/2 , 110 , Color.create( 0xffff0000u ) , 16 , 64 );
			g.drawFilledRect( 64 , HEIGHT / 2 , WIDTH - 128 ,  HEIGHT / 2 -64  , Color.create( 0x55800000u ) , 0 );
			return true;
		} //
	} //
	public const int GAME        = 0;
	public const int STAGESELECT = 2;
	protected int _returnValue = 0;
	public int returnValue(){return _returnValue;}
	protected int _selectedValue = 0;
	public int selectedValue(){return _selectedValue;}

	private GameStage _stage;
	private GameParam _param;
	private IState _caller;
	private Player _player;
	private int _frameCnt;
	protected IGamePad _gamepad;
	protected IMenuItem[] _items; 
	protected EnumMenuItem _startMenu;
	protected MenuItem _editMenu , _replayMenu , _configMenu , _quitMenu;
	protected string[] _stageValues;


	protected GameState _gameState;
	protected IMenuItem _activeItem ;
	protected IState _nextState ;
	protected ConfigMenuState _configState;
	protected EditorState _editorState;
	protected ReplaySelectState _replayState;
	protected DemoGameState _demoState;
	
	protected IGraphics _graphics;
	protected Background _background;
	
	protected PreviewStage _pstage;
	

	public this( GameState state , GameParam param , IGamePad pad , IGraphics g ){
		_gameState = state;
		_param     = param;
		_gamepad   = pad;
		_graphics  = g;
	} //

	public IState call( IState caller ) {
		_caller = caller;
		_nextState = this;
		_gamepad.reset();
		initMenu();
		_frameCnt = 0;
		_stage = _gameState.stage;
		if ( GameConfig.autoDemo ) {
			_demoState.autoDemo = true;
			return _demoState.call( this );
		}
		if ( !(caller is _configState ) || !SoundManager.background.busy ) {
			ISoundSprite bgm = SoundManager.background.play( GameConfig.titleBgm , 0 );
		}
		return this;
	} //
	
	private void initMenu(){
		if ( _startMenu is null ) {
			Console.write("Create StartMenu...");
			_background = new Background();
			_pstage		= new PreviewStage( _graphics );
			_demoState	= new DemoGameState( this , _graphics );
			_startMenu  = new EnumMenuItem("GAME START");
			_editMenu   = new MenuItem("EDIT MODE");
			_replayMenu = new MenuItem("REPLAY");
			_configMenu = new MenuItem("OPTION");
			_quitMenu   = new MenuItem("QUIT");
			
			_items ~= _startMenu;
			_items ~= _editMenu;
			_items ~= _replayMenu;
			_items ~= _configMenu;
			_items ~= _quitMenu;
			MenuItemConnector.connectVertical( _items );


			_activeItem = _startMenu.activate();
			
			int xx = WIDTH / 2 , yy = HEIGHT /2;
			_startMenu.moveTo(  xx , yy += 25 );
			_editMenu.moveTo(   xx , yy += 25 );
			_replayMenu.moveTo( xx , yy += 25 );
			_configMenu.moveTo( xx , yy += 25 );
			_quitMenu.moveTo(   xx , yy += 25 );
		
			_startMenu.setSelectHandler(  &onStartMenuSelect );
			_editMenu.setSelectHandler(   &onEditMenuSelect );
			_replayMenu.setSelectHandler( &onReplayMenuSelect );
			_startMenu.setChangedHandler( &onStartMenuChange );
			_configMenu.setSelectHandler( &onConfigMenuSelect );
			_quitMenu.setSelectHandler(  &onQuitMenuSelect );
			for ( int i = 1 ; i <= GameConfig.stageLength ; i++ ) {
				_stageValues ~= std.string.toString(i);
			}

			Console.writeln("OK");
		}
		_startMenu.setValues( "GAME START" , _stageValues[0..GameConfig.bestStage] , GameConfig.lastStage -1 );
		setStageNumber( GameConfig.lastStage );
	} //

	int _cntY = 0, _cntX = 0;
	public IState action() {
		_frameCnt ++;
		_pstage.action();
		foreach ( int i , IMenuItem item ; _items  ) {
			item.action();
		} //
		if ( _frameCnt > 30 ) {
			if ( _gamepad.y != 0 )  _cntY++; 
			else					_cntY = 0;
			if ( _gamepad.x != 0 )  _cntX++;
			else					_cntX = 0;
			if ( _cntY % 10 == 1 ) {
				_activeItem = ( _gamepad.y > 0 ) ? _activeItem.down  : _activeItem.up;
			}
			if ( _cntX % 10 == 1 || ( _cntX > 60 && _cntX % 3 == 1 ) ) {
				_activeItem = ( _gamepad.x > 0 ) ? _activeItem.right : _activeItem.left;
			}
		}

		if ( !SoundManager.background.busy 
//				|| _frameCnt > 30 
				) {
			return _demoState.call( this );
		}

		if ( _gamepad.getButton( 0 ) != 0 ) {
			_activeItem.select();
		}
		

		return _nextState;
	} //

	public IState draw( IGraphics g ) {
		foreach ( int i , IMenuItem item ; _items  ) {
			item.drawingEntry( g );
		} //
//		if ( _pstage.frameCnt < 10 ) _pstage.zoomOut();
		_pstage.drawingEntry( g ) ;
		_background.drawingEntry( g );
		g.draw();
		return this;
	} //

	public int setStageNumber( int num ) {
		string src    = format( "%s/stage%04d.txt" , GameConfig.stageDir , num );
		string defSrc = GameConfig.stageDir ~ "/stage0001.txt";
		if ( !exists( src ) ) {
			src = defSrc;
			num = 1;
			if( !exists( src ) ) {
				return false;
			}
		}
		_pstage.loadStageFromFile( src );
		return num;
	} //



	public bool onKeyDown( int keyCode ){
		switch ( keyCode ) {
			case KeyCode.UP:
				_gamepad.y = -1;
				break;
			case KeyCode.DOWN:
				_gamepad.y =  1;
				break;
			case KeyCode.LEFT:
				_gamepad.x = -1;
				break;
			case KeyCode.RIGHT:
				_gamepad.x =  1;
				break;
			case KeyCode.Z:
			case KeyCode.ENTER:
				_gamepad.setButton( 0 , 1 );
				break;
			case KeyCode.X:
				_gamepad.setButton( 1 , 1 );
				break;
			default:
				break;
		}
		return true;
	} //
	public bool onKeyUp( int keyCode ){
		switch ( keyCode ) {
			case KeyCode.UP:
				_gamepad.y = 0;
				break;
			case KeyCode.DOWN:
				_gamepad.y = 0;
				break;
			case KeyCode.LEFT:
				_gamepad.x = 0;
				break;
			case KeyCode.RIGHT:
				_gamepad.x = 0;
				break;
			case KeyCode.Z:
			case KeyCode.ENTER:
				_gamepad.setButton( 0 , 0 );
				break;
			case KeyCode.X:
				_gamepad.setButton( 1 , 0 );
				break;
			default:
				break;
		}
		return true;
	} //
	public bool onJoyAxis( int deviceId , int axis , int delta ){
		if ( axis == JOYAXIS_X ) {
			if( delta != 0 ) _gamepad.x = ( delta > 0 ) ? 1 : -1;
			else			 _gamepad.x = 0;
		}
		if ( axis == JOYAXIS_Y ){
			if( delta != 0 ) _gamepad.y = ( delta > 0 ) ? 1 : -1;
			else			 _gamepad.y = 0;
		}
		return true;
	} //
	
	public bool onJoyButtonDown( int id , int button ) {
		_gamepad.setButton( GameConfig.getButtonMap( button ) , 1 );
		return true;
	} //

	public bool onJoyButtonUp( int id , int button ) {
		_gamepad.setButton( GameConfig.getButtonMap( button ) , 0 );
		return true;
	} //


	public void onStartMenuSelect( IMenuItem im ) {
		_returnValue = STAGESELECT;
		_selectedValue = cast(int)atoi( _startMenu.value );
		_nextState = _gameState.call( this );
		Console.writeln("START GAME!");
	} //
	
	public void onStartMenuChange( EnumMenuItem im , string selectedValue , int selectedIndex ) {
		int num = cast(int)atoi( selectedValue );
		setStageNumber( num );
	} //
	public void onEditMenuSelect( IMenuItem im ) {
		if ( _editorState is null )	_editorState = new EditorState( this , _graphics );
		_nextState = _editorState.call( this );
		Console.writeln("EDIT!");
	} //

	public void onReplayMenuSelect( IMenuItem im ) {
		if ( _replayState is null )	_replayState = new ReplaySelectState( this , _graphics );
		_nextState = _replayState.call( this );
		Console.writeln("REPLAY!");
	} //

	public void onConfigMenuSelect( IMenuItem im ) {
		if ( _configState is null ) _configState = new ConfigMenuState( _gamepad );
		_nextState = _configState.call( this );
		Console.writeln("CONFIG!");
	} //
	
	public void onQuitMenuSelect(IMenuItem im){
		_nextState = null;
		Console.writeln("QUIT!");
	}


} //



/**
* 
*/

private class ConfigMenuState : BasicState {
	private IState _caller;
	private int _frameCnt;
	protected IGamePad _gamepad;
	protected string[] _cpuValues , _volumeValues;
	protected IMenuItem[] _items; 
	protected MenuItem _buttonMenu ,_digLeftMenu , _digRightMenu , _pauseMenu , _giveupMenu , _backMenu , _resetMenu;
	protected EnumMenuItem _bgmMenu , _sndMenu , _cpuMenu;
	
	protected GameState _gameState;
	protected IMenuItem _activeItem ;
	protected IState _nextState ;

	protected const int WIDTH = 240 , HEIGHT = 480;
	protected int _buttonFlag = -1;

	public this( IGamePad pad){
		_gamepad   = pad;
	} //

	public IState call( IState caller ) {
		_caller = caller;
		_nextState = this;
		_buttonFlag = -1;
		_gamepad.reset();
		initMenu();
		_frameCnt = 0;
		return this;
	} //
	
	private void initMenu(){
		if ( _digLeftMenu is null ) {
			Console.write("Create ConfigMenu...");

			_cpuMenu      = new EnumMenuItem("CPU");
			_bgmMenu      = new EnumMenuItem("BGM VOLUME   ");
			_sndMenu      = new EnumMenuItem("SOUND VOLUME ");

			_buttonMenu   = new MenuItem("*BUTTON CONFIG*");

			alias std.string.toString ts;
			_digLeftMenu  = new MenuItem("DIG  LEFT    " ~ ts( GameConfig.getButtonMapR( 0 ) ) );
			_digRightMenu = new MenuItem("DIG  RIGHT   " ~ ts( GameConfig.getButtonMapR( 1 ) ) );
			_giveupMenu   = new MenuItem("GIVEUP       " ~ ts( GameConfig.getButtonMapR( 8 ) ) );
			_pauseMenu    = new MenuItem("PAUSE        " ~ ts( GameConfig.getButtonMapR( 9 ) ) );
			_backMenu     = new MenuItem("BACK");
			_resetMenu    = new MenuItem("RESET");

			// _buttonMenuはグループ化しない
			_items ~= _cpuMenu;
			_items ~= _bgmMenu;
			_items ~= _sndMenu;
			_items ~= _digLeftMenu;
			_items ~= _digRightMenu;
			_items ~= _giveupMenu;
			_items ~= _pauseMenu;
			_items ~= _backMenu;
			_items ~= _resetMenu;
			MenuItemConnector.connectVertical( _items );

			_items ~= _buttonMenu;

			_cpuValues = [ "NORMAL", "FC" , "PC" , "GBA" ];
			for ( int i = 0 ; i <= 100 ; i+= 5 )
				_volumeValues ~=  std.string.toString( 1000 + i )[ 1..length ];

			_activeItem = _backMenu.activate();

			int xx = WIDTH / 2 , yy = HEIGHT / 3;
			_cpuMenu.moveTo(      xx , yy += 25 );
			_bgmMenu.moveTo(      xx , yy += 25 );
			_sndMenu.moveTo(      xx , yy += 25 );

			_buttonMenu.moveTo(   xx , yy += 50 );
			_digLeftMenu.moveTo(  xx , yy += 25 );
			_digRightMenu.moveTo( xx , yy += 25 );
			_giveupMenu.moveTo(   xx , yy += 25 );
			_pauseMenu.moveTo(    xx , yy += 25 );
			_backMenu.moveTo(     xx , yy += 25 );
			_resetMenu.moveTo(     xx , yy += 25 );

			_cpuMenu.setChangedHandler( &onCpuMenuChange );
			_bgmMenu.setChangedHandler( &onBgmVolumeChange );
			_sndMenu.setChangedHandler( &onSndVolumeChange );

			_backMenu.setSelectHandler( &onBackMenuSelect );
			_resetMenu.setSelectHandler( &onResetMenuSelect );

			_resetMenu.normalColor  = Color.create(0xff00ffff);

			Console.writeln("OK");
		}
			_cpuMenu.setValues( "CPU       "      , _cpuValues    , GameConfig.cpu );
			_bgmMenu.setValues( "BGM VOLUME   " , _volumeValues , format("%03d" , GameConfig.bgmVolume ) );
			_sndMenu.setValues( "SOUND VOLUME " , _volumeValues , format("%03d" , GameConfig.soundVolume ) );
	} //

	int _cntY = 0, _cntX = 0;
	public IState action() {
		_frameCnt ++;
		foreach ( int i , IMenuItem item ; _items  ) {
			item.action();
		} //
		
		if ( _frameCnt > 30 ) {
			if ( _gamepad.y != 0 )  _cntY++; 
			else					_cntY = 0;
			if ( _gamepad.x != 0 )  _cntX++;
			else					_cntX = 0;
			if ( _cntY % 10 == 1 ) {
				_activeItem = ( _gamepad.y > 0 ) ? _activeItem.down  : _activeItem.up;
			}
			if ( _cntX % 10 == 1 ) {
				_activeItem = ( _gamepad.x > 0 ) ? _activeItem.right : _activeItem.left;
			}
		}
		if ( _buttonFlag >= 0 ) {
			string v = std.string.toString( _buttonFlag );
			alias std.string.toString ts;
			if ( _activeItem is _digLeftMenu ) {
				_digLeftMenu.text = (  "DIG  LEFT    " ~ ts( _buttonFlag ) );
				GameConfig.setButtonMap( _buttonFlag , 0 );
			}
			if ( _activeItem is _digRightMenu ) {
				_digRightMenu.text = ( "DIG  RIGHT   " ~ ts( _buttonFlag ) );
				GameConfig.setButtonMap( _buttonFlag , 1 );
			}
			if ( _activeItem is _giveupMenu ) {
				_giveupMenu.text    = ("GIVEUP       " ~ ts( _buttonFlag ) );
				GameConfig.setButtonMap( _buttonFlag , 8 );
			}
			if ( _activeItem is _pauseMenu ) {
				_pauseMenu.text   = (  "PAUSE        " ~ ts( _buttonFlag ) );
				GameConfig.setButtonMap( _buttonFlag , 9 );
			}

			}

		if ( _gamepad.getButton( 0 ) > 0 || _gamepad.getButton( 1 ) > 0 )
			_activeItem.select();

		_buttonFlag = -1;


		return _nextState;
	} //

	public IState draw( IGraphics g ) {
		foreach ( int i , IMenuItem item ; _items  ) {
			item.drawingEntry( g );
		} //

		g.setViewport(    0 , 0, WIDTH , HEIGHT );
		g.drawFilledRect( 0 , 0 , WIDTH , HEIGHT , Color.create(0x88000000u) );
		string txt = "SYSTEM CONFIG";
		int	   fw = 16 , fh = 64;
		int     cx = ( WIDTH - fw * txt.length ) / 2;
		g.drawText( txt , cx , 60 , Color.create( 0x66ffffffu ) , fw , fh );
		g.drawText( txt , cx , 50 , Color.create( 0xffff0000u ) , fw , fh );
		g.draw();
		return this;
	} //

	public bool onKeyDown( int keyCode ){
		switch ( keyCode ) {
			case KeyCode.UP:
				_gamepad.y = -1;
				break;
			case KeyCode.DOWN:
				_gamepad.y =  1;
				break;
			case KeyCode.LEFT:
				_gamepad.x = -1;
				break;
			case KeyCode.RIGHT:
				_gamepad.x =  1;
				break;
			case KeyCode.Z:
			case KeyCode.ENTER:
				_gamepad.setButton( 0 , 1 );
				break;
			case KeyCode.X:
				_gamepad.setButton( 1 , 1 );
				break;
			default:
				break;
		}
		return true;
	} //

	public bool onKeyUp( int keyCode ){
		switch ( keyCode ) {
			case KeyCode.UP:
				_gamepad.y = 0;
				break;
			case KeyCode.DOWN:
				_gamepad.y = 0;
				break;
			case KeyCode.LEFT:
				_gamepad.x = 0;
				break;
			case KeyCode.RIGHT:
				_gamepad.x = 0;
				break;
			case KeyCode.Z:
			case KeyCode.ENTER:
				_gamepad.setButton( 0 , 0 );
				break;
			case KeyCode.X:
				_gamepad.setButton( 1 , 0 );
				break;
			default:
				break;
		}
		return true;
	} //
	public bool onJoyAxis( int deviceId , int axis , int delta ){
		if ( axis == JOYAXIS_X ) {
			if( delta != 0 ) _gamepad.x = ( delta > 0 ) ? 1 : -1;
			else			 _gamepad.x = 0;
		}
		if ( axis == JOYAXIS_Y ){
			if( delta != 0 ) _gamepad.y = ( delta > 0 ) ? 1 : -1;
			else			 _gamepad.y = 0;
		}
		return true;
	} //
	
	public bool onJoyButtonDown( int id , int button ) {
		_gamepad.setButton( button , 1 );
		return true;
	} //

	public bool onJoyButtonUp( int id , int button ) {
		_buttonFlag = button;
		_gamepad.setButton( button , 0 );
		return true;
	} //

	
	public void onCpuMenuChange( EnumMenuItem im , string selectedValue , int selectedIndex ) {
		GameConfig.cpu = selectedValue;
	} //

	public void onBgmVolumeChange( EnumMenuItem im , string selectedValue , int selectedIndex ) {
		int val = cast(int)atoi( selectedValue );
		SoundManager.bgmVolume = val;
		GameConfig.bgmVolume = val;
	} //
	public void onSndVolumeChange( EnumMenuItem im , string selectedValue , int selectedIndex ) {
		int val = cast(int)atoi( selectedValue );
		SoundManager.soundVolume = val;
		SoundManager.getSprite().play(GameConfig.goldSound , 0).release();
		GameConfig.soundVolume = val;
	} //


	public void onBackMenuSelect(IMenuItem im){
		_nextState = _caller.call( this );
		Console.writeln("QUIT!");
	} //
	
	public void onResetMenuSelect( IMenuItem im ) {
		alias std.string.toString ts;
		for ( int i = 0 ; i < 9 ; i++ ) 
			GameConfig.setButtonMap( i , i );
			_digLeftMenu.text = (  "DIG  LEFT    " ~ ts( 0 ) );
			_digRightMenu.text = ( "DIG  RIGHT   " ~ ts( 1 ) );
			_giveupMenu.text    = ("GIVEUP       " ~ ts( 2 ) );
			_pauseMenu.text   = (  "PAUSE        " ~ ts( 3 ) );
			int val = 100;
			SoundManager.soundVolume = val;
			SoundManager.getSprite().play(GameConfig.goldSound , 0).release();
			GameConfig.soundVolume = val;
			SoundManager.bgmVolume = val;
			GameConfig.bgmVolume = val;

			GameConfig.cpu = "NORMAL";
			_cpuMenu.setValues( "CPU       "    , _cpuValues    , "NORMAL" );
			_bgmMenu.setValues( "BGM VOLUME   " , _volumeValues , format("%03d" , 100 ) );
			_sndMenu.setValues( "SOUND VOLUME " , _volumeValues , format("%03d" , 100 ) );
		
	} //
	
	


} //

